﻿#include "eventloop.h"
#include <cassert>
#include <sys/eventfd.h>
#include "epoller.h"
#include "channel.h"
#include "timerwheel.h"
#include "log.h"


int EventLoop::initEventfd()
{
    int eventfd = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
    if(eventfd < 0)
    {
        LOG(Fatal, "eventfd error");
        abort();
    }
    return eventfd;
}

void EventLoop::readEventfd()
{
    uint64_t out = 0;
    int ret = ::read(m_eventfd, &out, sizeof(out));
    if (ret < 0) 
    {
        if (errno == EINTR || errno == EAGAIN)
        {
            return;
        }
        LOG(Fatal, "READ EVENTFD ERROR");
        abort();
    }
}

void EventLoop::wakeupEventfd()
{
    uint64_t one = 1;
    int ret = ::write(m_eventfd, &one, sizeof(one));
    if (ret < 0)
    {
        if (errno == EINTR || errno == EAGAIN)
        {
            return;
        }
        LOG(Fatal, "WRITE EVENTFD ERROR");
        abort();
    }
}

EventLoop::EventLoop()
    : m_tid(std::this_thread::get_id())
    , m_eventfd(initEventfd())
    , m_eventfd_channel(new Channel(this, m_eventfd))
    , m_epoller(new Epoller())
    , m_timerwheel(new TimerWheel(this))
{
    m_eventfd_channel->setReadCallback(std::bind(&EventLoop::readEventfd, this));
    m_eventfd_channel->enableRead();
}

EventLoop::~EventLoop()
{

}

void EventLoop::start()
{
    while(true)
    {
        std::vector<Channel*> activeChannels;
        // 1. 获取就绪事件
        m_epoller->waitEvent(activeChannels);
        // 2. 处理事件
        for(auto channel : activeChannels)
        {
            channel->handleEvent();
        }
        // 3. 执行任务
        runAllTask();
    }
}

bool EventLoop::isInLoopThread() const
{
    return m_tid == std::this_thread::get_id();
}

void EventLoop::pushInLoop(const TaskFunc_t &task)
{
    // 1. 将任务压入任务队列                      
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        m_tasks.push_back(task);
    }
    // 2. 唤醒事件循环
    // NOTE: 有任务入队，唤醒事件循环
    wakeupEventfd();
}

void EventLoop::assertInLoop()
{
    assert(isInLoopThread());
}

void EventLoop::updateChannel(Channel *channel)
{
    return m_epoller->updateEvent(channel);
}

void EventLoop::removeChannel(Channel *channel)
{
    return m_epoller->removeEvent(channel);
}

void EventLoop::runInLoop(const TaskFunc_t &task)
{
    if(isInLoopThread())
    {
        return task();
    }
    return pushInLoop(task);
}

void EventLoop::runAllTask()
{
    std::vector<TaskFunc_t> tasks;
    {
        std::unique_lock<std::mutex> lock(m_mutex);
        tasks.swap(m_tasks);
    }
    for(auto &task : tasks)
    {
        task();
    }
}

void EventLoop::addTimerTask(uint64_t id, uint32_t timeout, const TaskFunc_t &task)
{
    m_timerwheel->addTimerTask(id, timeout, task);
}

void EventLoop::refreshTimerTask(uint64_t id)
{
    m_timerwheel->refreshTimerTask(id);
}

void EventLoop::cancelTimerTask(uint64_t id)
{
    m_timerwheel->cancelTimerTask(id);  
}

bool EventLoop::hasTimerTask(uint64_t id)
{
    return m_timerwheel->hasTimerTask(id);
}